/*
 * File:   ConnectionManager.cpp
 * Author: wilq
 *
 * Created on June 13, 2012, 6:51 PM
 */

#include "ConnectionManager.h"

ConnectionManager& ConnectionManager::getInstance()
{
    static ConnectionManager instance;
    return instance;
}

ServerStorageProtocol* ConnectionManager::getStorageConnection(int32_t storageId, bool check)
{
	FUNCTION_TRACK
    boost::lock_guard<boost::mutex> lock(m_mutex);
	std::map<uint32_t, ServerStorageProtocol*>::iterator it = connectionsStorages.find(storageId);
	if (it == connectionsStorages.end())
	{
		return NULL;
	}
	if (check)
	{
		NetworkPacket request(CSNetworkLib::PACKET_SYNC);
		if (!it->second->SendPacket(request))
		{
			connectionsStorages.erase(it);
			return NULL;
		}
	}
	return it->second;
}

ServerClientProtocol* ConnectionManager::getUserConnection(int32_t userId, bool check)
{
	FUNCTION_TRACK
    boost::lock_guard<boost::mutex> lock(m_mutex);
	std::map<uint32_t, ServerClientProtocol*>::iterator it = connectionsClients.find(userId);
	while (it != connectionsClients.end())
	{
        if (check)
        {
            NetworkPacket request(CSNetworkLib::PACKET_SYNC);
            if (!it->second->SendPacket(request))
            {
                connectionsClients.erase(it);
                ++it;
                continue;
            }
        }
        return it->second;
    }
    return NULL;
}

bool ConnectionManager::PutStorage(uint32_t id, ServerStorageProtocol* ptr)
{
	FUNCTION_TRACK
    boost::lock_guard<boost::mutex> lock(m_mutex);
	std::map<uint32_t, ServerStorageProtocol*>::iterator it = connectionsStorages.find(id);
	if (it != connectionsStorages.end())
	{
		return false;
	}
	connectionsStorages[id] = ptr;
	return true;
}

bool ConnectionManager::PutClient(uint32_t id, ServerClientProtocol* ptr)
{
	FUNCTION_TRACK
    boost::lock_guard<boost::mutex> lock(m_mutex);
	std::map<uint32_t, ServerClientProtocol*>::iterator it = connectionsClients.find(id);
	if (it != connectionsClients.end())
	{
		return false;
	}
	connectionsClients.insert(std::pair<uint32_t, ServerClientProtocol*>(id,ptr));
	return true;
}

void ConnectionManager::RemoveStorage(uint32_t id)
{
	FUNCTION_TRACK
    boost::lock_guard<boost::mutex> lock(m_mutex);
	std::map<uint32_t, ServerStorageProtocol*>::iterator it = connectionsStorages.find(id);
	if (it != connectionsStorages.end())
	{
		connectionsStorages.erase(it);
	}
}

void ConnectionManager::RemoveClient(uint32_t id, ServerClientProtocol* ptr)
{
	FUNCTION_TRACK
    boost::lock_guard<boost::mutex> lock(m_mutex);
	std::map<uint32_t, ServerClientProtocol*>::iterator it = connectionsClients.find(id);
	while (it != connectionsClients.end())
	{
        if (ptr == it->second)
        {
            connectionsClients.erase(it);
            return;
        }
        ++it;
	}
}

EType ConnectionManager::SyncInfo(uint32_t storageId, const std::string &link)
{
    if (link.empty()) return ETYPE_ERROR;
    ServerStorageProtocol *s = getStorageConnection(storageId);
    if (!s) return ETYPE_ERROR;
    return s->GetInfo(link);
}

EType ConnectionManager::SyncInfo(uint32_t storageId, const std::string &parentLink, const std::string &name)
{
    if (parentLink.empty() || name.empty()) return ETYPE_ERROR;
    ServerStorageProtocol *s = getStorageConnection(storageId);
    if (!s) return ETYPE_ERROR;
    return s->GetInfo(parentLink, name);
}

EType ConnectionManager::SyncFolder(uint32_t storageId, const std::string &link)
{
    if (link.empty()) return ETYPE_ERROR;
    ServerStorageProtocol *s = getStorageConnection(storageId);
    if (!s) return ETYPE_ERROR;
    return s->FolderSync(link, false);
}

bool ConnectionManager::PutHandle(uint32_t clientHandle, uint32_t storageHandle, ServerClientProtocol* client, ServerStorageProtocol* storage)
{
    if (0 == clientHandle || 0 == storageHandle || NULL == client || NULL == storage)
        return false;
    boost::lock_guard<boost::mutex> lock(m_mutex);
    handles.insert(std::pair< std::pair<uint32_t, ServerClientProtocol*>, boost::shared_ptr<SStorageHandle> >(std::pair<uint32_t, ServerClientProtocol*>(clientHandle, client), boost::shared_ptr<SStorageHandle>(new SStorageHandle(storage, storageHandle))));
    return true;
}

bool ConnectionManager::RemoveHandle(uint32_t clientHandle, ServerClientProtocol* client)
{
    if (0 == clientHandle || NULL == client)
    {
        return false;
    }
    boost::lock_guard<boost::mutex> lock(m_mutex);
    std::map< std::pair<uint32_t, ServerClientProtocol*>, boost::shared_ptr<SStorageHandle> >::iterator it = handles.find(std::pair<uint32_t, ServerClientProtocol*>(clientHandle, client));
    if (it!=handles.end())
    {
        handles.erase(it);
        return true;
    }
    return false;
}

boost::shared_ptr<ConnectionManager::SStorageHandle> ConnectionManager::GetHandle(uint32_t clientHandle, ServerClientProtocol* client)
{
    if (0 == clientHandle || NULL == client)
    {
        return boost::shared_ptr<SStorageHandle>();
    }
    boost::lock_guard<boost::mutex> lock(m_mutex);
    std::map< std::pair<uint32_t, ServerClientProtocol*>, boost::shared_ptr<SStorageHandle> >::iterator it = handles.find(std::pair<uint32_t, ServerClientProtocol*>(clientHandle, client));
    if (it!=handles.end())
    {
        return it->second;
    }
    return boost::shared_ptr<SStorageHandle>();
}

void ConnectionManager::CloseHandlesClient(ServerClientProtocol* client)
{
    boost::lock_guard<boost::mutex> lock(m_mutex);
    std::map< std::pair<uint32_t, ServerClientProtocol*>, boost::shared_ptr<SStorageHandle> >::iterator it = handles.begin();
    while(it!=handles.end())
    {
        if (it->first.second == client)
        {
            it->second->storage->FileClose(it->second->handle);
            handles.erase(it++);
        }
        else
        {
            ++it;
        }
    }
}

void ConnectionManager::CloseHandlesStorage(ServerStorageProtocol* storage)
{
    boost::lock_guard<boost::mutex> lock(m_mutex);
    std::map< std::pair<uint32_t, ServerClientProtocol*>, boost::shared_ptr<SStorageHandle> >::iterator it = handles.begin();
    while(it!=handles.end())
    {
        if (it->second->storage == storage)
        {
            handles.erase(it++);
        }
        else
        {
            ++it;
        }
    }
}